import dayjs, {ManipulateType} from "dayjs";
import {extractStr, fillTime} from "./format";
import isBetween from "dayjs/plugin/isBetween";
import minMax from 'dayjs/plugin/minMax';
import {KDate} from "@/types/utils";

dayjs.extend(isBetween);
dayjs.extend(minMax);

export function getToday() {
    return getDateInfo(new Date());
}

// 获取一个日期的详细信息
export function getDateInfo(date: KDate, format: string = 'YYYY-MM-DD') {
    let newDate = dayjs(date);
    return {
        year: newDate.year(),
        month: newDate.month() + 1, // dayjs的月份是从0开始的，所以需要加1
        date: newDate.date(),
        format: newDate.format(format)
    }
}

/*
 * @Author: EDY
 * @Date: 2024/6/7
 * @LastEditors: EDY
 * @Description: 获取日期数组最大最小相隔的日期
 * @Params:
 */
export function getRangeDates(dateArray: KDate[], format: string = "YYYY-MM-DD"): string[] {
    // 将日期字符串和时间戳转换为 Day.js 对象
    const dayjsArray = dateArray.map((date) => {
        if (typeof date === 'string') {
            return dayjs(date, format);
        } else {
            return dayjs(date);
        }
    });

    // 找出最小和最大日期
    const minDate = dayjs.min(dayjsArray)!;
    const maxDate = dayjs.max(dayjsArray)!;

    if (!minDate.isValid() || !maxDate.isValid()) {
        throw new Error('Invalid date format');
    }

    const datesRange = [];
    const daysDifference = maxDate.diff(minDate, 'day') + 1;

    datesRange.push(minDate.format(format)); // 添加最小日期

    for (let i = 1; i < daysDifference; i++) {
        const currentDate = minDate.add(i, 'day').format(format);
        datesRange.push(currentDate);
    }

    datesRange.push(maxDate.format(format)); // 添加最大日期

    return datesRange;
}


//日期数组排序
export function sortDateArray(dateArray: KDate[], format = 'YYYY-MM-DD'): (string | number)[] {
    // 将日期字符串转换为 Day.js 对象
    const dayjsArray = dateArray.map((date) => {
        if (typeof date === 'string') {
            return dayjs(date, format);
        } else {
            return dayjs(date);
        }
    });

    // 对 Day.js 对象数组进行排序
    const sortedDayjsArray = dayjsArray.sort((a, b) => a.valueOf() - b.valueOf());

    // 将排序后的 Day.js 对象转换回字符串或时间戳
    const sortedDateArray = sortedDayjsArray.map((dayjsObj) => {
        if (dayjsObj.isValid()) {
            return dayjsObj.format('YYYY-MM-DD');
        } else {
            return dayjsObj.valueOf();
        }
    });

    return sortedDateArray;
}


/*
 * @Author: EDY
 * @Date: 2024/6/7
 * @LastEditors: EDY
 * @Description: 日期格式化
 * @Params:
 */
export function formatDate(date: KDate, format = "YYYY-MM-DD hh:mm:ss") {
    return dayjs(date).format(format);
}

/*
 * @Author: EDY
 * @Date: 2024/6/7
 * @LastEditors: EDY
 * @Description: 格式化时间戳
 * @Params:
 */
export function timeFormat(timestamp: number, format = "YYYY-MM-DD") {
    // 判断时间戳的级别
    const isMilliseconds = String(timestamp).length > 10;

    // 创建 dayjs 对象
    const dayjsObj = isMilliseconds ? dayjs(timestamp) : dayjs.unix(timestamp);

    return dayjsObj.format(format);
};

/*
 * @Author: EDY
 * @Date: 2024/6/6
 * @LastEditors: EDY
 * @Description: 获取日期时间段
 * @Params:
 */
export function getDateRange(value: number, unit: string, format = "YYYY-MM-DD") {
    let us = extractStr(unit, "lately");
    unit = us ? us[0] : unit;
    let range: string[] = [];
    // let dayAdd = dayjs().add;
    switch (unit) {
        case "day": {
            const date = dayjs().add(value, unit).format(format);
            range = fillTime(date) as string[];
            break;
        }
        case "lately": {
            const startDate = dayjs().add(value, us![1] as ManipulateType).format(format);
            const endDate = dayjs().format(format);
            range = fillTime([startDate, endDate]);
            break;
        }
        case "week": {
            // 获取本周的日期范围
            const startOfWeek = dayjs().add(value, unit).startOf(unit).format(format);
            const endOfWeek = dayjs().add(value, unit).endOf(unit).format(format);
            console.log("获取本周的日期范围", startOfWeek, endOfWeek)
            range = fillTime([startOfWeek, endOfWeek]);
            break;
        }
        case "month": {
            const month = dayjs().add(value, unit);
            const monthStart = month.startOf(unit).format(format);
            const monthEnd = month.endOf(unit).format(format);
            range = fillTime([monthStart, monthEnd]);
            break;
        }
    }
    return range;
}


/**
 * 判断给定日期是否在指定的时间段范围内
 * @param {string} dateStr 要判断的日期字符串，格式为 'YYYY-MM-DD'
 * @param {string} rangeStr 时间段范围字符串，格式为 'YYYY-MM-DD-YYYY-MM-DD'
 * @returns {boolean} 日期是否在时间段范围内
 */
export function isDateInRange(
    dateStr: string,
    rangeStr: string,
    decollator:string = "/"
) {
    const date = dayjs(dateStr);
    const [startStr, endStr] = rangeStr.split(decollator);
    return date.isBetween(startStr, endStr, "day", "[]");
}

// 日期偏移
export function offest(date: KDate, diffDay: number, action = "add") {
    return (dayjs(date) as any)[action](diffDay, "day");
}

// 获取时间段内最大的日期
export function getMaxRangeDate(dates: KDate[]) {
    let date = dates.reduce((max, date) => {
        const currentDate = dayjs(date);
        return currentDate.isAfter(max) ? currentDate : max;
    }, dayjs("1970-01-01")); // 设置一个最小的初始日期
    return formatDate(date);
}

// 日期是否大于今日
export function hasAfterToday(date: KDate) {
    const today = dayjs();
    return dayjs(date).isAfter(today);
}

/**
 * 计算给定时间段内相差的天数
 * @param {string} rangeStr 时间段范围字符串,格式为 'YYYY-MM-DD/YYYY-MM-DD'
 * @returns {number} 时间段内相差的天数
 */
export function diffInDateRange(rangeStr: string, decollator = "/") {
    const {start, end} = parseDateRange(rangeStr, decollator);
    return end.diff(start, "days") + 1; // 加 1 是为了包含开始日期
}

/**
 * 解析时间段范围字符串为对象
 * @param {string} rangeStr 时间段范围字符串,格式为 'YYYY-MM-DD/YYYY-MM-DD'
 * @returns {{ start: Dayjs, end: Dayjs }} 包含开始和结束时间的对象
 */
export function parseDateRange(rangeStr: string, decollator = "/") {
    const [startStr, endStr] = rangeStr.split(decollator);
    return {
        start: dayjs(startStr),
        end: dayjs(endStr),
    };
}

/**
 * 比较两个时间段范围的大小
 * @param {string} range1Str 第一个时间段范围字符串,格式为 'YYYY-MM-DD/YYYY-MM-DD'
 * @param {string} range2Str 第二个时间段范围字符串,格式为 'YYYY-MM-DD/YYYY-MM-DD'
 * @param {string} decollator 分隔符
 * @returns {number} 负数表示 range1 小于 range2, 0 表示相等, 正数表示 range1 大于 range2
 */
export function compareDateRanges(
    range1Str: string,
    range2Str: string,
    decollator: string = "/"
) {
    const range1 = parseDateRange(range1Str, decollator);
    const range2 = parseDateRange(range2Str, decollator);

    const startDiff = range1.start.diff(range2.start, "days");
    const endDiff = range1.end.diff(range2.end, "days");

    if (startDiff === 0 && endDiff === 0) {
        return 0; // 时间段相等
    } else if (startDiff < 0 || (startDiff === 0 && endDiff < 0)) {
        return -1; // range1 小于 range2
    } else {
        return 1; // range1 大于 range2
    }
}